์๋ฐ์คํฌ๋ฆฝํธ ๋ฉ๋ชจ์ด์ ์ด์ ๊ธฐ๋ฒ, ์บ์ฑ ์ ๋ต ๋ฐ ์ค์ ์์ ๋ฅผ ํตํด ์ฝ๋ ์ฑ๋ฅ์ ์ต์ ํํ์ธ์. ๋ ๋น ๋ฅธ ์คํ์ ์ํ ๋ฉ๋ชจ์ด์ ์ด์ ํจํด ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ฐฐ์ธ ์ ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ฉ๋ชจ์ด์ ์ด์ ํจํด: ์บ์ฑ ์ ๋ต๊ณผ ์ฑ๋ฅ ํฅ์
์ํํธ์จ์ด ๊ฐ๋ฐ ๋ถ์ผ์์ ์ฑ๋ฅ์ ๊ฐ์ฅ ์ค์ํ ์์์ ๋๋ค. ํ๋ก ํธ์๋ ์น ๊ฐ๋ฐ๋ถํฐ Node.js๋ฅผ ์ฌ์ฉํ ์๋ฒ์ฌ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๋ฅด๊ธฐ๊น์ง ๋ค์ํ ํ๊ฒฝ์์ ์ฌ์ฉ๋๋ ๋ค์ฌ๋ค๋ฅํ ์ธ์ด์ธ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ถ๋๋ฝ๊ณ ํจ์จ์ ์ธ ์คํ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ข ์ข ์ต์ ํ๊ฐ ํ์ํฉ๋๋ค. ํน์ ์๋๋ฆฌ์ค์์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฒ ์ค ํ๋๊ฐ ๋ฐ๋ก ๋ฉ๋ชจ์ด์ ์ด์ (memoization)์ ๋๋ค.
๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฃผ๋ก ๋น์ฉ์ด ๋ง์ด ๋๋ ํจ์ ํธ์ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ณ , ๋์ผํ ์ ๋ ฅ๊ฐ์ด ๋ค์ ๋ฐ์ํ์ ๋ ์บ์๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ์ฌ ์ปดํจํฐ ํ๋ก๊ทธ๋จ์ ์๋๋ฅผ ๋์ด๋ ๋ฐ ์ฌ์ฉ๋๋ ์ต์ ํ ๊ธฐ๋ฒ์ ๋๋ค. ๋ณธ์ง์ ์ผ๋ก, ์ด๊ฒ์ ํจ์๋ฅผ ํน์ ๋์์ผ๋ก ํ๋ ์บ์ฑ์ ํ ํํ์ ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ ํน์ง์ ๊ฐ์ง ํจ์์ ํนํ ํจ๊ณผ์ ์ ๋๋ค:
- ์์ ํจ์(Pure): ๋ถ์ ํจ๊ณผ(side effect) ์์ด ์ค์ง ์ ๋ ฅ๊ฐ์ ์ํด์๋ง ๋ฐํ๊ฐ์ด ๊ฒฐ์ ๋๋ ํจ์.
- ๊ฒฐ์ ๋ก ์ (Deterministic): ๋์ผํ ์ ๋ ฅ์ ๋ํด ํญ์ ๋์ผํ ์ถ๋ ฅ์ ์์ฑํ๋ ํจ์.
- ๋น์ฉ์ด ๋์(Expensive): ๊ณ์ฐ์ด ๊ณ์ฐ์ ์ผ๋ก ์ง์ฝ์ ์ด๊ฑฐ๋ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ํจ์(์: ์ฌ๊ท ํจ์, ๋ณต์กํ ๊ณ์ฐ).
์ด ๊ธ์์๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฉ๋ชจ์ด์ ์ด์ ๊ฐ๋ ์ ํ๊ตฌํ๊ณ , ๋ค์ํ ํจํด, ์บ์ฑ ์ ๋ต, ๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ตฌํ์ ํตํด ์ป์ ์ ์๋ ์ฑ๋ฅ ํฅ์์ ๋ํด ์์ธํ ์์๋ด ๋๋ค. ๋ค์ํ ์๋๋ฆฌ์ค์์ ๋ฉ๋ชจ์ด์ ์ด์ ์ ํจ๊ณผ์ ์ผ๋ก ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ๊ธฐ ์ํด ์ค์ ์์ ๋ฅผ ์ดํด๋ณผ ๊ฒ์ ๋๋ค.
๋ฉ๋ชจ์ด์ ์ด์ ์ ์ดํด: ํต์ฌ ๊ฐ๋
๋ฉ๋ชจ์ด์ ์ด์ ์ ํต์ฌ์ ์บ์ฑ ์๋ฆฌ๋ฅผ ํ์ฉํ๋ ๊ฒ์ ๋๋ค. ๋ฉ๋ชจ์ด์ ์ด์ ๋ ํจ์๊ฐ ํน์ ์ธ์ ์งํฉ์ผ๋ก ํธ์ถ๋๋ฉด, ๋จผ์ ํด๋น ์ธ์์ ๋ํ ๊ฒฐ๊ณผ๊ฐ ์ด๋ฏธ ๊ณ์ฐ๋์ด ์บ์(์ผ๋ฐ์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด ๋๋ Map)์ ์ ์ฅ๋์๋์ง ํ์ธํฉ๋๋ค. ๊ฒฐ๊ณผ๊ฐ ์บ์์ ์์ผ๋ฉด ์ฆ์ ๋ฐํ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด, ํจ์๋ ๊ณ์ฐ์ ์คํํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํ ๋ค์ ๋ฐํํฉ๋๋ค.
ํต์ฌ ์ด์ ์ ์ค๋ณต ๊ณ์ฐ์ ํผํ๋ ๋ฐ ์์ต๋๋ค. ๋ง์ฝ ํจ์๊ฐ ๋์ผํ ์ ๋ ฅ๊ฐ์ผ๋ก ์ฌ๋ฌ ๋ฒ ํธ์ถ๋๋ค๋ฉด, ๋ฉ๋ชจ์ด์ ์ด์ ๋ ๋ฒ์ ์ ๊ณ์ฐ์ ๋จ ํ ๋ฒ๋ง ์ํํฉ๋๋ค. ์ดํ์ ํธ์ถ์ ์บ์์์ ์ง์ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ํ๋ฏ๋ก, ํนํ ๊ณ์ฐ ๋น์ฉ์ด ๋ง์ด ๋๋ ์์ ์์ ์๋นํ ์ฑ๋ฅ ํฅ์์ ๊ฐ์ ธ์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฉ๋ชจ์ด์ ์ด์ ํจํด
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฉ๋ชจ์ด์ ์ด์ ์ ๊ตฌํํ๊ธฐ ์ํด ์ฌ๋ฌ ํจํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ฐ์ฅ ์ผ๋ฐ์ ์ด๊ณ ํจ๊ณผ์ ์ธ ๋ช ๊ฐ์ง๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1. ํด๋ก์ ๋ฅผ ์ด์ฉํ ๊ธฐ๋ณธ ๋ฉ๋ชจ์ด์ ์ด์
์ด๋ ๋ฉ๋ชจ์ด์ ์ด์ ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ํด๋ก์ ๋ฅผ ํ์ฉํ์ฌ ํจ์ ์ค์ฝํ ๋ด์ ์บ์๋ฅผ ์ ์งํฉ๋๋ค. ์บ์๋ ์ผ๋ฐ์ ์ผ๋ก ํค๊ฐ ํจ์ ์ธ์๋ฅผ ๋ํ๋ด๊ณ ๊ฐ์ด ํด๋น ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ด๋ ๊ฐ๋จํ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๋๋ค.
function memoize(func) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args); // ์ธ์๋ฅผ ์ํ ๊ณ ์ ํค ์์ฑ
if (cache[key]) {
return cache[key]; // ์บ์๋ ๊ฒฐ๊ณผ ๋ฐํ
} else {
const result = func.apply(this, args); // ๊ฒฐ๊ณผ ๊ณ์ฐ
cache[key] = result; // ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅ
return result; // ๊ฒฐ๊ณผ ๋ฐํ
}
};
}
// ์์ : ํฉํ ๋ฆฌ์ผ ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
const memoizedFactorial = memoize(factorial);
console.time('First call');
console.log(memoizedFactorial(5)); // ๊ณ์ฐํ๊ณ ์บ์ํจ
console.timeEnd('First call');
console.time('Second call');
console.log(memoizedFactorial(5)); // ์บ์์์ ๊ฐ์ ธ์ด
console.timeEnd('Second call');
์ค๋ช :
- `memoize` ํจ์๋ `func` ํจ์๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์ต๋๋ค.
- ์ค์ฝํ ๋ด์ `cache` ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค (ํด๋ก์ ์ฌ์ฉ).
- ์๋ณธ ํจ์๋ฅผ ๊ฐ์ธ๋ ์๋ก์ด ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ด ๋ํผ ํจ์๋ `JSON.stringify(args)`๋ฅผ ์ฌ์ฉํ์ฌ ํจ์ ์ธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ์ ํ ํค๋ฅผ ์์ฑํฉ๋๋ค.
- `cache`์ `key`๊ฐ ์๋์ง ํ์ธํฉ๋๋ค. ์์ผ๋ฉด ์บ์๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.
- `key`๊ฐ ์์ผ๋ฉด ์๋ณธ ํจ์๋ฅผ ํธ์ถํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ `cache`์ ์ ์ฅํ ๋ค์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
ํ๊ณ์ :
- `JSON.stringify`๋ ๋ณต์กํ ๊ฐ์ฒด์ ๋ํด ๋๋ฆด ์ ์์ต๋๋ค.
- ์ธ์ ์์๊ฐ ๋ค๋ฅด๊ฑฐ๋ ํค๋ ๊ฐ์ง๋ง ์์๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ๋ฐ๋ ํจ์์์๋ ํค ์์ฑ์ด ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
- `JSON.stringify(NaN)`์ด `null`์ ๋ฐํํ๋ฏ๋ก `NaN`์ ์ ๋๋ก ์ฒ๋ฆฌํ์ง ๋ชปํฉ๋๋ค.
2. ์ฌ์ฉ์ ์ ์ ํค ์์ฑ๊ธฐ๋ฅผ ์ด์ฉํ ๋ฉ๋ชจ์ด์ ์ด์
`JSON.stringify`์ ํ๊ณ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, ํจ์์ ์ธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ์ ํ ํค๋ฅผ ์์ฑํ๋ ์ฌ์ฉ์ ์ ์ ํค ์์ฑ๊ธฐ ํจ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ ์บ์ ์ธ๋ฑ์ฑ ๋ฐฉ๋ฒ์ ๋ ์ธ๋ฐํ๊ฒ ์ ์ดํ๊ณ ํน์ ์๋๋ฆฌ์ค์์ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
function memoizeWithKey(func, keyGenerator) {
const cache = {};
return function(...args) {
const key = keyGenerator(...args);
if (cache[key]) {
return cache[key];
} else {
const result = func.apply(this, args);
cache[key] = result;
return result;
}
};
}
// ์์ : ๋ ์ซ์๋ฅผ ๋ํ๋ ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
function add(a, b) {
console.log('Calculating...');
return a + b;
}
// add ํจ์๋ฅผ ์ํ ์ฌ์ฉ์ ์ ์ ํค ์์ฑ๊ธฐ
function addKeyGenerator(a, b) {
return `${a}-${b}`;
}
const memoizedAdd = memoizeWithKey(add, addKeyGenerator);
console.log(memoizedAdd(2, 3)); // ๊ณ์ฐํ๊ณ ์บ์ํจ
console.log(memoizedAdd(2, 3)); // ์บ์์์ ๊ฐ์ ธ์ด
console.log(memoizedAdd(3, 2)); // ๊ณ์ฐํ๊ณ ์บ์ํจ (๋ค๋ฅธ ํค)
์ค๋ช :
- ์ด ํจํด์ ๊ธฐ๋ณธ ๋ฉ๋ชจ์ด์ ์ด์ ๊ณผ ์ ์ฌํ์ง๋ง, ์ถ๊ฐ์ ์ธ ์ธ์์ธ `keyGenerator`๋ฅผ ๋ฐ์ต๋๋ค.
- `keyGenerator`๋ ์๋ณธ ํจ์์ ๋์ผํ ์ธ์๋ฅผ ๋ฐ์ ๊ณ ์ ํ ํค๋ฅผ ๋ฐํํ๋ ํจ์์ ๋๋ค.
- ์ด๋ฅผ ํตํด ํนํ ๋ณต์กํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ์์ ํ๋ ํจ์์ ๋ํด ๋ ์ ์ฐํ๊ณ ํจ์จ์ ์ธ ํค ์์ฑ์ด ๊ฐ๋ฅํฉ๋๋ค.
3. Map์ ์ด์ฉํ ๋ฉ๋ชจ์ด์ ์ด์
์๋ฐ์คํฌ๋ฆฝํธ์ `Map` ๊ฐ์ฒด๋ ์บ์๋ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋ ๋ฐ ๋ ๊ฐ๋ ฅํ๊ณ ๋ค์ฌ๋ค๋ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ผ๋ฐ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๋ฌ๋ฆฌ, `Map`์ ๊ฐ์ฒด์ ํจ์๋ฅผ ํฌํจํ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ํค๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ธ์๋ฅผ ๋ฌธ์์ด๋ก ๋ณํํ ํ์๋ฅผ ์์ ๊ณ ํค ์์ฑ์ ๋จ์ํํฉ๋๋ค.
function memoizeWithMap(func) {
const cache = new Map();
return function(...args) {
const key = args.join('|'); // ๊ฐ๋จํ ํค ์์ฑ (๋ ์ ๊ตํด์ง ์ ์์)
if (cache.has(key)) {
return cache.get(key);
} else {
const result = func.apply(this, args);
cache.set(key, result);
return result;
}
};
}
// ์์ : ๋ฌธ์์ด์ ์ฐ๊ฒฐํ๋ ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
function concatenate(str1, str2) {
console.log('Concatenating...');
return str1 + str2;
}
const memoizedConcatenate = memoizeWithMap(concatenate);
console.log(memoizedConcatenate('hello', 'world')); // ๊ณ์ฐํ๊ณ ์บ์ํจ
console.log(memoizedConcatenate('hello', 'world')); // ์บ์์์ ๊ฐ์ ธ์ด
์ค๋ช :
- ์ด ํจํด์ `Map` ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์บ์๋ฅผ ์ ์ฅํฉ๋๋ค.
- `Map`์ ๊ฐ์ฒด์ ํจ์๋ฅผ ํฌํจํ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ํค๋ก ์ฌ์ฉํ ์ ์์ด, ์ผ๋ฐ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๋นํด ๋ ํฐ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
- `Map` ๊ฐ์ฒด์ `has` ๋ฐ `get` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๊ฐ ์บ์๋ ๊ฐ์ ํ์ธํ๊ณ ๊ฒ์ํฉ๋๋ค.
4. ์ฌ๊ท์ ๋ฉ๋ชจ์ด์ ์ด์
๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ๊ท ํจ์๋ฅผ ์ต์ ํํ๋ ๋ฐ ํนํ ํจ๊ณผ์ ์ ๋๋ค. ์ค๊ฐ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํจ์ผ๋ก์จ ์ค๋ณต ๊ณ์ฐ์ ํผํ๊ณ ์คํ ์๊ฐ์ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค.
function memoizeRecursive(func) {
const cache = {};
function memoized(...args) {
const key = String(args);
if (cache[key]) {
return cache[key];
} else {
cache[key] = func(memoized, ...args);
return cache[key];
}
}
return memoized;
}
// ์์ : ํผ๋ณด๋์น ์์ด ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
function fibonacci(memoized, n) {
if (n <= 1) {
return n;
}
return memoized(n - 1) + memoized(n - 2);
}
const memoizedFibonacci = memoizeRecursive(fibonacci);
console.time('First call');
console.log(memoizedFibonacci(10)); // ๊ณ์ฐํ๊ณ ์บ์ํจ
console.timeEnd('First call');
console.time('Second call');
console.log(memoizedFibonacci(10)); // ์บ์์์ ๊ฐ์ ธ์ด
console.timeEnd('Second call');
์ค๋ช :
- `memoizeRecursive` ํจ์๋ `func` ํจ์๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์ต๋๋ค.
- ์ค์ฝํ ๋ด์ `cache` ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
- ์๋ณธ ํจ์๋ฅผ ๊ฐ์ธ๋ ์๋ก์ด `memoized` ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
- `memoized` ํจ์๋ ์ฃผ์ด์ง ์ธ์์ ๋ํ ๊ฒฐ๊ณผ๊ฐ ์ด๋ฏธ ์บ์์ ์๋์ง ํ์ธํฉ๋๋ค. ์์ผ๋ฉด ์บ์๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.
- ๊ฒฐ๊ณผ๊ฐ ์บ์์ ์์ผ๋ฉด, ์๋ณธ ํจ์๋ฅผ ํธ์ถํ ๋ `memoized` ํจ์ ์์ฒด๋ฅผ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌํฉ๋๋ค. ์ด๋ฅผ ํตํด ์๋ณธ ํจ์๊ฐ ์ฌ๊ท์ ์ผ๋ก ์์ (์ ๋ฉ๋ชจ์ด์ ์ด์ ๋ ๋ฒ์ )์ ํธ์ถํ ์ ์์ต๋๋ค.
- ๊ฒฐ๊ณผ๋ ์บ์์ ์ ์ฅ๋ ํ ๋ฐํ๋ฉ๋๋ค.
5. ํด๋์ค ๊ธฐ๋ฐ ๋ฉ๋ชจ์ด์ ์ด์
๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ฒฝ์ฐ, ํด๋์ค ๋ด์์ ๋ฉ๋ชจ์ด์ ์ด์ ์ ๊ตฌํํ์ฌ ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํ ์ ์์ต๋๋ค. ์ด๋ ๋์ผํ ์ธ์๋ก ์์ฃผ ํธ์ถ๋๋ ๊ณ์ฐ ๋น์ฉ์ด ๋์ ๋ฉ์๋์ ์ ์ฉํ ์ ์์ต๋๋ค.
class MemoizedClass {
constructor() {
this.cache = {};
}
memoizeMethod(func) {
return (...args) => {
const key = JSON.stringify(args);
if (this.cache[key]) {
return this.cache[key];
} else {
const result = func.apply(this, args);
this.cache[key] = result;
return result;
}
};
}
// ์์ : ์ซ์์ ๊ฑฐ๋ญ์ ๊ณฑ์ ๊ณ์ฐํ๋ ๋ฉ์๋ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
power(base, exponent) {
console.log('Calculating power...');
return Math.pow(base, exponent);
}
}
const memoizedInstance = new MemoizedClass();
const memoizedPower = memoizedInstance.memoizeMethod(memoizedInstance.power);
console.log(memoizedPower(2, 3)); // ๊ณ์ฐํ๊ณ ์บ์ํจ
console.log(memoizedPower(2, 3)); // ์บ์์์ ๊ฐ์ ธ์ด
์ค๋ช :
- `MemoizedClass`๋ ์์ฑ์์์ `cache` ์์ฑ์ ์ ์ํฉ๋๋ค.
- `memoizeMethod`๋ ํจ์๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ์ ํด๋น ํจ์์ ๋ฉ๋ชจ์ด์ ์ด์ ๋ ๋ฒ์ ์ ๋ฐํํ๋ฉฐ, ๊ฒฐ๊ณผ๋ ํด๋์ค์ `cache`์ ์ ์ฅ๋ฉ๋๋ค.
- ์ด๋ฅผ ํตํด ํด๋์ค์ ํน์ ๋ฉ์๋๋ฅผ ์ ํ์ ์ผ๋ก ๋ฉ๋ชจ์ด์ ์ด์ ํ ์ ์์ต๋๋ค.
์บ์ฑ ์ ๋ต
๊ธฐ๋ณธ์ ์ธ ๋ฉ๋ชจ์ด์ ์ด์ ํจํด์ ๋์ด, ์บ์ ๋์์ ์ต์ ํํ๊ณ ํฌ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ๋ค์ํ ์บ์ฑ ์ ๋ต์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ ๋ต์ ์บ์๊ฐ ํจ์จ์ ์ผ๋ก ์ ์ง๋๊ณ ๊ณผ๋ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํ์ง ์๋๋ก ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
1. LRU(Least Recently Used) ์บ์
LRU ์บ์๋ ์บ์๊ฐ ์ต๋ ํฌ๊ธฐ์ ๋๋ฌํ์ ๋ ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉ๋์ง ์์ ํญ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค. ์ด ์ ๋ต์ ๊ฐ์ฅ ์์ฃผ ์ ๊ทผํ๋ ๋ฐ์ดํฐ๋ ์บ์์ ๋จ์์๊ฒ ํ๊ณ , ๋ ์์ฃผ ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ๋ ํ๊ธฐ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (this.cache.has(key)) {
const value = this.cache.get(key);
this.cache.delete(key); // ์ต๊ทผ์ ์ฌ์ฉ๋์์์ ํ์ํ๊ธฐ ์ํด ๋ค์ ์ฝ์
this.cache.set(key, value);
return value;
} else {
return undefined;
}
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
}
this.cache.set(key, value);
if (this.cache.size > this.capacity) {
// ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉ๋์ง ์์ ํญ๋ชฉ ์ ๊ฑฐ
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}
}
// ์ฌ์ฉ ์์ :
const lruCache = new LRUCache(3); // ์ฉ๋ 3
lruCache.put('a', 1);
lruCache.put('b', 2);
lruCache.put('c', 3);
console.log(lruCache.get('a')); // 1 ('a'๋ฅผ ๋งจ ๋ค๋ก ์ด๋)
lruCache.put('d', 4); // 'b'๊ฐ ์ ๊ฑฐ๋จ
console.log(lruCache.get('b')); // undefined
console.log(lruCache.get('a')); // 1
console.log(lruCache.get('c')); // 3
console.log(lruCache.get('d')); // 4
์ค๋ช :
- ์ฝ์ ์์๋ฅผ ์ ์งํ๋ `Map`์ ์ฌ์ฉํ์ฌ ์บ์๋ฅผ ์ ์ฅํฉ๋๋ค.
- `get(key)`์ ๊ฐ์ ๊ฒ์ํ๊ณ ํค-๊ฐ ์์ ๋ค์ ์ฝ์ ํ์ฌ ์ต๊ทผ์ ์ฌ์ฉ๋์์์ ํ์ํฉ๋๋ค.
- `put(key, value)`์ ํค-๊ฐ ์์ ์ฝ์ ํฉ๋๋ค. ์บ์๊ฐ ๊ฐ๋ ์ฐจ๋ฉด ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉ๋์ง ์์ ํญ๋ชฉ(`Map`์ ์ฒซ ๋ฒ์งธ ํญ๋ชฉ)์ด ์ ๊ฑฐ๋ฉ๋๋ค.
2. LFU(Least Frequently Used) ์บ์
LFU ์บ์๋ ์บ์๊ฐ ๊ฐ๋ ์ฐผ์ ๋ ๊ฐ์ฅ ์ ๊ฒ ์ฌ์ฉ๋ ํญ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค. ์ด ์ ๋ต์ ๋ ์์ฃผ ์ ๊ทผํ๋ ๋ฐ์ดํฐ์ ์ฐ์ ์์๋ฅผ ๋์ด ์บ์์ ๋จ์์๋๋ก ๋ณด์ฅํฉ๋๋ค.
class LFUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
this.frequencies = new Map();
this.minFrequency = 0;
}
get(key) {
if (!this.cache.has(key)) {
return undefined;
}
const frequency = this.frequencies.get(key);
this.frequencies.set(key, frequency + 1);
return this.cache.get(key);
}
put(key, value) {
if (this.capacity <= 0) {
return;
}
if (this.cache.has(key)) {
this.cache.set(key, value);
this.get(key);
return;
}
if (this.cache.size >= this.capacity) {
this.evict();
}
this.cache.set(key, value);
this.frequencies.set(key, 1);
this.minFrequency = 1;
}
evict() {
let minFreq = Infinity;
for (const frequency of this.frequencies.values()) {
minFreq = Math.min(minFreq, frequency);
}
const keysToRemove = [];
this.frequencies.forEach((freq, key) => {
if (freq === minFreq) {
keysToRemove.push(key);
}
});
const keyToRemove = keysToRemove[0];
this.cache.delete(keyToRemove);
this.frequencies.delete(keyToRemove);
}
}
// ์ฌ์ฉ ์์ :
const lfuCache = new LFUCache(2);
lfuCache.put('a', 1);
lfuCache.put('b', 2);
console.log(lfuCache.get('a')); // 1, frequency(a) = 2
lfuCache.put('c', 3); // frequency(b) = 1์ด๋ฏ๋ก 'b'๋ฅผ ์ ๊ฑฐ
console.log(lfuCache.get('b')); // undefined
console.log(lfuCache.get('a')); // 1, frequency(a) = 3
console.log(lfuCache.get('c')); // 3, frequency(c) = 2
์ค๋ช :
- ๋ ๊ฐ์ `Map` ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค: `cache`๋ ํค-๊ฐ ์์ ์ ์ฅํ๊ณ , `frequencies`๋ ๊ฐ ํค์ ์ ๊ทผ ๋น๋๋ฅผ ์ ์ฅํฉ๋๋ค.
- `get(key)`์ ๊ฐ์ ๊ฒ์ํ๊ณ ๋น๋ ์๋ฅผ ์ฆ๊ฐ์ํต๋๋ค.
- `put(key, value)`์ ํค-๊ฐ ์์ ์ฝ์ ํฉ๋๋ค. ์บ์๊ฐ ๊ฐ๋ ์ฐจ๋ฉด ๊ฐ์ฅ ์ ๊ฒ ์ฌ์ฉ๋ ํญ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค.
- `evict()`๋ ์ต์ ๋น๋ ์๋ฅผ ์ฐพ์ ํด๋น ํค-๊ฐ ์์ `cache`์ `frequencies` ๋ชจ๋์์ ์ ๊ฑฐํฉ๋๋ค.
3. ์๊ฐ ๊ธฐ๋ฐ ๋ง๋ฃ
์ด ์ ๋ต์ ์ผ์ ์๊ฐ์ด ์ง๋ ํ ์บ์๋ ํญ๋ชฉ์ ๋ฌดํจํํฉ๋๋ค. ์ด๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๊ฐ ์ค๋๋๊ฑฐ๋ ์ ํจํ์ง ์๊ฒ ๋๋ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ช ๋ถ ๋์๋ง ์ ํจํ API ์๋ต์ ์บ์ฑํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
function memoizeWithExpiration(func, ttl) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
const cached = cache.get(key);
if (cached && cached.expiry > Date.now()) {
return cached.value;
} else {
const result = func.apply(this, args);
cache.set(key, { value: result, expiry: Date.now() + ttl });
return result;
}
};
}
// ์์ : 5์ด ๋ง๋ฃ ์๊ฐ์ ๊ฐ์ง ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
ํ๊ธฐ
function getDataFromAPI(endpoint) {
console.log(`Fetching data from ${endpoint}...`);
// ์ง์ฐ์ ๊ฐ์ง API ํธ์ถ ์๋ฎฌ๋ ์ด์
return new Promise(resolve => {
setTimeout(() => {
resolve(`Data from ${endpoint}`);
}, 1000);
});
}
const memoizedGetData = memoizeWithExpiration(getDataFromAPI, 5000); // TTL: 5์ด
async function testExpiration() {
console.log(await memoizedGetData('/users')); // ๊ฐ์ ธ์ค๊ณ ์บ์ํจ
console.log(await memoizedGetData('/users')); // ์บ์์์ ๊ฐ์ ธ์ด
setTimeout(async () => {
console.log(await memoizedGetData('/users')); // 5์ด ํ ๋ค์ ๊ฐ์ ธ์ด
}, 6000);
}
testExpiration();
์ค๋ช :
- `memoizeWithExpiration` ํจ์๋ `func` ํจ์์ ๋ฐ๋ฆฌ์ด ๋จ์์ TTL(time-to-live) ๊ฐ์ ์ ๋ ฅ์ผ๋ก ๋ฐ์ต๋๋ค.
- ์บ์๋ ๊ฐ๊ณผ ํจ๊ป ๋ง๋ฃ ํ์์คํฌํ๋ฅผ ์ ์ฅํฉ๋๋ค.
- ์บ์๋ ๊ฐ์ ๋ฐํํ๊ธฐ ์ ์ ๋ง๋ฃ ํ์์คํฌํ๊ฐ ์์ง ๋ฏธ๋์ธ์ง ํ์ธํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์บ์๋ฅผ ๋ฌดํจํํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์ต๋๋ค.
์ฑ๋ฅ ํฅ์ ๋ฐ ๊ณ ๋ ค์ฌํญ
๋ฉ๋ชจ์ด์ ์ด์ ์ ํนํ ๋์ผํ ์ ๋ ฅ์ผ๋ก ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถ๋๋ ๊ณ์ฐ ๋น์ฉ์ด ๋์ ํจ์์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. ์ฑ๋ฅ ํฅ์์ ๋ค์ ์๋๋ฆฌ์ค์์ ๊ฐ์ฅ ๋๋๋ฌ์ง๋๋ค:
- ์ฌ๊ท ํจ์: ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ๊ท ํธ์ถ์ ์๋ฅผ ๊ทน์ ์ผ๋ก ์ค์ฌ ์ง์์ ์ธ ์ฑ๋ฅ ํฅ์์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
- ์ค๋ณต๋๋ ํ์ ๋ฌธ์ ๊ฐ ์๋ ํจ์: ๋ฉ๋ชจ์ด์ ์ด์ ์ ํ์ ๋ฌธ์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ณ ํ์ํ ๋ ์ฌ์ฌ์ฉํ์ฌ ์ค๋ณต ๊ณ์ฐ์ ํผํ ์ ์์ต๋๋ค.
- ๋์ผํ ์ ๋ ฅ์ด ๋น๋ฒํ ํจ์: ๋ฉ๋ชจ์ด์ ์ด์ ์ ๊ฐ ๊ณ ์ ํ ์ ๋ ฅ ์งํฉ์ ๋ํด ํจ์๊ฐ ํ ๋ฒ๋ง ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
ํ์ง๋ง ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ์ฉํ ๋๋ ๋ค์๊ณผ ๊ฐ์ ์ฅ๋จ์ ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ๋ฉ๋ชจ๋ฆฌ ์๋น: ๋ฉ๋ชจ์ด์ ์ด์ ์ ํจ์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํฉ๋๋ค. ๊ฐ๋ฅํ ์ ๋ ฅ์ด ๋ง์ ํจ์๋ ๋ฉ๋ชจ๋ฆฌ ์์์ด ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
- ์บ์ ๋ฌดํจํ: ๊ธฐ๋ฐ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์บ์๋ ๊ฒฐ๊ณผ๊ฐ ์ค๋๋ ์ ์์ต๋๋ค. ์บ์๊ฐ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ก ์บ์ ๋ฌดํจํ ์ ๋ต์ ๊ตฌํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ๋ณต์ก์ฑ: ๋ฉ๋ชจ์ด์ ์ด์ ์ ๊ตฌํํ๋ฉด ํนํ ๋ณต์กํ ์บ์ฑ ์ ๋ต์ ๊ฒฝ์ฐ ์ฝ๋์ ๋ณต์ก์ฑ์ด ์ถ๊ฐ๋ ์ ์์ต๋๋ค. ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ์ฉํ๊ธฐ ์ ์ ์ฝ๋์ ๋ณต์ก์ฑ๊ณผ ์ ์ง ๊ด๋ฆฌ์ฑ์ ์ ์คํ๊ฒ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ค์ฉ์ ์ธ ์์ ๋ฐ ์ฌ์ฉ ์ฌ๋ก
๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํด ๋ค์ํ ์๋๋ฆฌ์ค์ ์ ์ฉ๋ ์ ์์ต๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ค์ฉ์ ์ธ ์์ ๋๋ค:
- ํ๋ก ํธ์๋ ์น ๊ฐ๋ฐ: ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น์ฉ์ด ๋ง์ด ๋๋ ๊ณ์ฐ์ ๋ฉ๋ชจ์ด์ ์ด์ ํ๋ฉด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ต์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ณต์กํ DOM ์กฐ์์ ์ํํ๊ฑฐ๋ ๋ ์ด์์ ์์ฑ์ ๊ณ์ฐํ๋ ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์ ํ ์ ์์ต๋๋ค.
- ์๋ฒ์ฌ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ : ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ๋ API ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํ์ฌ ์๋ฒ ๋ถํ๋ฅผ ์ค์ด๊ณ ์๋ต ์๊ฐ์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ ๋ถ์: ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ค๊ฐ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ์ฌ ๋ฐ์ดํฐ ๋ถ์ ์์ ์ ์๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ํต๊ณ ๋ถ์์ด๋ ๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ํํ๋ ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์ ํ ์ ์์ต๋๋ค.
- ๊ฒ์ ๊ฐ๋ฐ: ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ถฉ๋ ๊ฐ์ง๋ ๊ฒฝ๋ก ์ฐพ๊ธฐ์ ๊ฐ์ด ์์ฃผ ์ฌ์ฉ๋๋ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ์ฌ ๊ฒ์ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
๋ฉ๋ชจ์ด์ ์ด์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ ๊ฐ๋ ฅํ ์ต์ ํ ๊ธฐ๋ฒ์ ๋๋ค. ๋น์ฉ์ด ๋ง์ด ๋๋ ํจ์ ํธ์ถ์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํจ์ผ๋ก์จ ์ค๋ณต ๊ณ์ฐ์ ํผํ๊ณ ์คํ ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค. ํ์ง๋ง ์ฑ๋ฅ ํฅ์๊ณผ ๋ฉ๋ชจ๋ฆฌ ์๋น, ์บ์ ๋ฌดํจํ, ์ฝ๋ ๋ณต์ก์ฑ ์ฌ์ด์ ์ฅ๋จ์ ์ ์ ์คํ๊ฒ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ํ ๋ฉ๋ชจ์ด์ ์ด์ ํจํด๊ณผ ์บ์ฑ ์ ๋ต์ ์ดํดํจ์ผ๋ก์จ, ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์ต์ ํํ๊ณ ๊ณ ์ฑ๋ฅ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํด ๋ฉ๋ชจ์ด์ ์ด์ ์ ํจ๊ณผ์ ์ผ๋ก ์ ์ฉํ ์ ์์ต๋๋ค.